package com.yanqu.road.server.manager.grandchild;

import com.yanqu.road.entity.grandchild.GrandChildExamData;
import com.yanqu.road.entity.grandchild.JoinExamGrandChild;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.logic.bussiness.grandchild.GrandChildBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.pb.grandchild.GrandChildProto;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.mina.util.ConcurrentHashSet;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 孙子科举考场
 */
public class GrandChildExamRoom {

    private static Logger logger = LogManager.getLogger(GrandChildExamRoom.class.getName());

    // 考场基础数据
    private GrandChildExamData grandChildExamData;

    // 参与孙子数据
    private List<JoinExamGrandChild> joinExamGrandChildren;

    // 参与孙子ID
    private Set<String> childIdSet = new ConcurrentHashSet<>();

    // 待同步参与数据
    private final List<GrandChildProto.JoinExamDataMsg.Builder> waitSyncJoinMsg = new ArrayList<>();

    public GrandChildExamRoom(GrandChildExamData grandChildExamData, List<JoinExamGrandChild> joinExamGrandChildren) {
        this.grandChildExamData = grandChildExamData;
        this.joinExamGrandChildren = joinExamGrandChildren;

        for (JoinExamGrandChild child : joinExamGrandChildren) {
            childIdSet.add(child.getId());
        }
    }

    /**
     * 参加科举
     */
    public int joinExam(long globalId, long serverId, JoinExamGrandChild child) {
        // 不是同一场
        if (grandChildExamData.getGlobalId() != globalId) {
            return GameErrorCode.E_GRAND_CHILD_EXAM_HAD_END;
        }
        // 是否包含自己区服
        if (!getServerIdSet().contains(serverId)) {
            return GameErrorCode.E_GRAND_CHILD_EXAM_GROUP_CHANGE;
        }

        synchronized (this) {
            // 是否重复参加
            if (childIdSet.contains(child.getId())) {
                return GameErrorCode.E_GRAND_CHILD_EXAM_REPEATED_JOIN;
            }
            // 是否结束
            if (isFinish()) {
                return GameErrorCode.E_GRAND_CHILD_EXAM_HAD_END;
            }
            // 是否满了
            if (isFull()) {
                finishExam();
                return GameErrorCode.E_GRAND_CHILD_EXAM_JOIN_COUNT_FULL;
            }

            // 参加
            child.setPos(joinExamGrandChildren.size()); // 从0开始
            child.setInsertOption();
            joinExamGrandChildren.add(child);
            childIdSet.add(child.getId());

            // 检查满了
            if (isFull()) {
                finishExam();
            }

            // 同步
            syncJoinExamMsg(child);
        }
        return 0;
    }

    /**
     * 参加科举信息同步给玩家
     */
    private void syncJoinExamMsg(JoinExamGrandChild child) {

        // 孙子msg
        GrandChildProto.JoinExamDataMsg.Builder childBuilder = GrandChildProto.JoinExamDataMsg.newBuilder();
        childBuilder.setAppearanceId(child.getAppearanceId());
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(child.getUserId());
        if (userBaseInfo == null) {
            userBaseInfo = new UserBaseInfo();
        }
        childBuilder.setUserBaseInfo(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        childBuilder.setPos(child.getPos());
        childBuilder.setUserId(child.getUserId());

        // 返回值
        synchronized (waitSyncJoinMsg) {
            waitSyncJoinMsg.add(childBuilder);
        }
    }

    /**
     * 同步参加科举消息
     */
    public void syncExamJoinMsg() {
        List<GrandChildProto.JoinExamDataMsg.Builder> list;

        synchronized (waitSyncJoinMsg) {
            list = new ArrayList<>(waitSyncJoinMsg);
            waitSyncJoinMsg.clear();
        }

        if (list.isEmpty()) {
            return;
        }

        GrandChildProto.SyncJoinExamDataMsg.Builder builder = GrandChildProto.SyncJoinExamDataMsg.newBuilder();
        builder.setExamNo(grandChildExamData.getGlobalId() + "");
        for (GrandChildProto.JoinExamDataMsg.Builder tmp : list) {
            builder.addData(tmp.build());
        }
        YanQuMessage message = YanQuMessageUtils.buildMessage(GameProtocol.S_GRAND_CHILD_SYNC_IMPERIAL_EXAM_JOIN_FROM_CROSS, builder);

        // 发送到各区服
        for (Long serverId : grandChildExamData.getServerList()) {
            MessageHelper.sendPacket(serverId, 0, message);
        }
    }

    /**
     * 同步科举考试结束
     */
    public void syncExamFinishMsg(List<Long> serverList) {
        GrandChildProto.CrossSyncExamFinishMsg.Builder builder = GrandChildProto.CrossSyncExamFinishMsg.newBuilder();
        builder.setNo(grandChildExamData.getGlobalId() + "");
        builder.setFinishTime(grandChildExamData.getFinishTime());

        ArrayList<JoinExamGrandChild> list = new ArrayList<>(joinExamGrandChildren);
        for (JoinExamGrandChild child : list) {
            GrandChildProto.ExamPupilResultMsg.Builder msg = GrandChildProto.ExamPupilResultMsg.newBuilder();
            msg.setAppearanceId(child.getAppearanceId());
            msg.setUserBaseInfo(PlayerBasePb.parsePlayerBaseTempMsg(CrossUserMgr.getUserBaseInfo(child.getUserId())));
            msg.setName(child.getNickName());
            msg.setEarnSpeed(child.getEarnSpeed().toString());
            msg.setTitle(child.getTitle());
            msg.setUserId(child.getUserId());
            msg.setId(child.getId());
            builder.addResult(msg);
        }

        YanQuMessage message = YanQuMessageUtils.buildMessage(GameProtocol.S_GRAND_CHILD_SYNC_EXAM_FINISH_FROM_CROSS, builder);
        for (Long serverId : serverList) {
            MessageHelper.sendPacket(serverId, 0, message);
        }
    }

    /**
     * 进入科举考场
     *
     * @param pageNo 第几页，从0开始，默认一页50个
     */
    public void enterExam(long serverId, long userId, int pageNo) {
        int startIndex = pageNo * 50;
        int endIndex = (pageNo + 1) * 50 - 1;
        List<JoinExamGrandChild> tmpList = new ArrayList<>(joinExamGrandChildren);

        GrandChildProto.ExamDataMsg.Builder builder = GrandChildProto.ExamDataMsg.newBuilder();
        builder.setExamNo(grandChildExamData.getGlobalId() + "");
        builder.setJoinNum(tmpList.size());
        builder.setSession(GrandChildMgr.getServerExamData(serverId).getSession(grandChildExamData.getGlobalId()));
        builder.setRemainingNum(GameConfig.GRAND_CHILD_EXAM_JOIN_MAX_NUM - tmpList.size());
        for (int i = startIndex; i <= endIndex && i < tmpList.size(); i++) {
            JoinExamGrandChild child = tmpList.get(i);
            GrandChildProto.JoinExamDataMsg.Builder tmp = GrandChildProto.JoinExamDataMsg.newBuilder();
            tmp.setAppearanceId(child.getAppearanceId());
            UserBaseInfo baseInfo = CrossUserMgr.getUserBaseInfo(child.getUserId());
            if (baseInfo == null) {
                baseInfo = new UserBaseInfo();
            }
            tmp.setUserBaseInfo(PlayerBasePb.parsePlayerBaseTempMsg(baseInfo));
            tmp.setPos(i);
            tmp.setUserId(child.getUserId());

            builder.addData(tmp);
        }

        // 返回
        GrandChildProto.EnterExamRespMsg.Builder tmp = GrandChildProto.EnterExamRespMsg.newBuilder();
        tmp.setRet(0);
        tmp.setData(builder);
        YanQuMessage message = YanQuMessageUtils.buildMessage(ClientProtocol.U_GRAND_CHILD_ENTER_IMPERIAL_EXAM, tmp);
        MessageHelper.sendPacket(serverId, userId, message);
    }

    public boolean isFull() {
        return joinExamGrandChildren.size() >= GameConfig.GRAND_CHILD_EXAM_JOIN_MAX_NUM;
    }

    public boolean isFinish() {
        return grandChildExamData.getFinishTime() != 0;
    }

    /**
     * 目前只生成名次  不发奖
     */
    public void dealExamResult() {
        Random random = new Random();

        // 拿配置
        List<Integer> titleCountList = StringUtils.stringToStringList(GameConfig.GRAND_CHILD_EXAM_REWARD, "\\|").stream().mapToInt(
                item -> Integer.valueOf(item.split(",")[0])
        ).boxed().collect(Collectors.toList());

        // 准备随机数组
        LinkedList<JoinExamGrandChild> tmpChildList = new LinkedList<>(joinExamGrandChildren);
        List<Long> weightList = new ArrayList<>();
        for (JoinExamGrandChild grandChild : tmpChildList) {
            long earn = grandChild.getEarnSpeed().longValue();
            int addition = 0;
            if (!StringUtils.isNullOrEmpty(grandChild.getBuff())) {
                addition += Integer.valueOf(grandChild.getBuff());
            }
            int parm = GameConfig.GRAND_CHILD_EXAM_PARM;
            long  value = (long) Math.pow(earn * (1000 + addition) / 1000.0 / 1000, parm / 1000.0);
            weightList.add(value);
        }

        // 随机中榜的孙子（title：1状元，2探花，...）
        int title = 0;
        for (int count : titleCountList) {
            title++;

            // 落榜后面处理
            if (count == -1) {
                break;
            }

            // 随机非落榜title
            for (int i = 0; i < count; i++) {

                if (tmpChildList.isEmpty() || weightList.isEmpty()) {
                    break; // 随机完了
                }

                int index = RandomHelper.getLongListRandomIndexByWeight(weightList, random);
                weightList.remove(index);
                JoinExamGrandChild remove = tmpChildList.remove(index);
                remove.setTitle(title); // 设置结果
            }

            if (tmpChildList.isEmpty() || weightList.isEmpty()) {
                break; // 随机完了
            }
        }
        // 其余的落榜
        for (JoinExamGrandChild child : tmpChildList) {
            child.setTitle(title);
        }

        // 状元加榜单
        for (JoinExamGrandChild child : joinExamGrandChildren) {
            if (child.getTitle() == 1) {
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(child.getUserId());
                if (userBaseInfo != null) {
                    GrandChildRankMgr.championCountChange(userBaseInfo.getServerId(), child.getUserId(), 1);
                } else {
                    logger.info("examNo = {}, can not find champion userBaseInfo! userId = {}, grandChildId = {}.",
                            getGlobalId(), child.getUserId(), child.getId());
                }
            }
        }
    }

    /**
     * 请求结果
     */
    public void getResult(long serverId, long userId, int type) {
        // 落榜title
        int luoBangTitle = StringUtils.stringToStringList(GameConfig.GRAND_CHILD_EXAM_REWARD, "\\|").size();

        GrandChildProto.ExamResultRewardRespMsg.Builder builder = GrandChildProto.ExamResultRewardRespMsg.newBuilder();
        builder.setExamNo(grandChildExamData.getGlobalId() + "");
        builder.setType(type);
        builder.setSession(GrandChildMgr.getServerExamData(serverId).getSession(grandChildExamData.getGlobalId()));
        // builder.setReward(""); // 这里不设置奖励
        // builder.setPatronsReward(""); // 这里不设置奖励

        for (JoinExamGrandChild child : new ArrayList<>(joinExamGrandChildren)) {
            if (type == 1 && child.getTitle() == luoBangTitle && child.getUserId() != userId) {
                // 科举放榜：中榜 + 自己未中榜
                continue;
            }
            if (type == 2 && child.getTitle() == luoBangTitle) {
                // 皇榜点击：中榜
                continue;
            }
            GrandChildProto.ExamPupilResultMsg.Builder msg = GrandChildProto.ExamPupilResultMsg.newBuilder();
            msg.setAppearanceId(child.getAppearanceId());
            msg.setUserBaseInfo(PlayerBasePb.parsePlayerBaseTempMsg(CrossUserMgr.getUserBaseInfo(child.getUserId())));
            msg.setName(child.getNickName());
            msg.setEarnSpeed(child.getEarnSpeed().toString());
            msg.setTitle(child.getTitle());
            msg.setUserId(child.getUserId());
            msg.setId(child.getId());
            builder.addResult(msg);
        }

        // 发送
        YanQuMessage message = YanQuMessageUtils.buildMessage(GameProtocol.S_GRAND_CHILD_GET_IMPERIAL_EXAM_RESULT_FROM_CROSS, builder);
        MessageHelper.sendPacket(serverId, userId, message);
    }

    /**
     * 结算
     */
    public void finishExam() {
        synchronized (this) {
            if (!isFinish()) {

                grandChildExamData.setFinishTime(System.currentTimeMillis()); // 标记完成

                if (joinExamGrandChildren.isEmpty()) {
                    GrandChildMgr.removeServerExamData(getGlobalId(), new HashSet<>(getServerIdSet())); // 标记空科举
                }

                GrandChildMgr.addToHandleExam(grandChildExamData.getGlobalId(), new HashSet<>(getServerIdSet())); // 添加到待结算

                syncExamJoinMsg(); // 先把最后加入的数据同步下去

                dealExamResult(); // 计算科举结果

                syncExamFinishMsg(new ArrayList<>(grandChildExamData.getServerList())); // 同步科举结束

                // 不在开启时间内结束，同步状态
                if (!GrandChildExamConfigMgr.isOpen()) {
                    GrandChildMgr.syncExamConfigMsg(new ArrayList<>(grandChildExamData.getServerList()));
                }
            }
        }
    }

    public long getGlobalId() {
        return grandChildExamData.getGlobalId();
    }

    public Set<Long> getServerIdSet() {
        return grandChildExamData.getServerList();
    }

    public List<JoinExamGrandChild> getJoinExamGrandChildren() {
        return joinExamGrandChildren;
    }

    public int getGroupId() {
        return grandChildExamData.getGroupId();
    }

    public long getOpenTime() {
        return grandChildExamData.getOpenTime();
    }

    public String getOpenTimeParam() {
        return grandChildExamData.getOpenTimeParam();
    }

    public void save() {
        if (grandChildExamData.isInsertOption()) {
            GrandChildBussiness.addGrandChildExamData(grandChildExamData);
        } else if (grandChildExamData.isUpdateOption()) {
            GrandChildBussiness.updateGrandChildExamData(grandChildExamData);
        }

        for (JoinExamGrandChild grandChild : new ArrayList<>(joinExamGrandChildren)) {
            if (grandChild.isInsertOption()) {
                GrandChildBussiness.addJoinExamGrandChild(grandChild);
            } else if (grandChild.isUpdateOption()) {
                GrandChildBussiness.updateJoinExamGrandChild(grandChild);
            }
        }
    }
}
